package com.example.rabbitmqprovider.direct.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;



@Slf4j
@Configuration
public class RabbitConfig {

    @Bean
    public RabbitTemplate createRabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate();
        rabbitTemplate.setConnectionFactory(connectionFactory);
       // Mandatory为true时,消息通过交换器无法匹配到队列会返回给生产者，为false时匹配不到会直接被丢弃
        rabbitTemplate.setMandatory(true);

        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             *  ConfirmCallback机制只确认消息是否到达exchange(交换器)，不保证消息可以路由到正确的queue;
             *  需要设置：publisher-confirm-type: CORRELATED；
             *  springboot版本较低 参数设置改成：publisher-confirms: true
             *
             *  以实现方法confirm中ack属性为标准，true到达
             *  config : 需要开启rabbitmq得ack publisher-confirm-type
             */
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                log.info("ConfirmCallback  确认结果 (true代表发送成功) : {}  消息唯一标识 : {} 失败原因 ：{}",ack,correlationData,cause);
            }
        });

        rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
            /**
             *  ReturnsCallback 消息机制用于处理一个不可路由的消息。在某些情况下，如果我们在发送消息的时候，当前的 exchange 不存在或者指定路由 key 路由不到，这个时候我们需要监听这种不可达的消息
             *   就需要这种return机制
             *
             *  config : 需要开启rabbitmq发送失败回退; publisher-returns 或rabbitTemplate.setMandatory(true); 设置为true
             */
            @Override
            public void returnedMessage(ReturnedMessage returned) {
//                实现接口ReturnCallback，重写 returnedMessage() 方法，
//                方法有五个参数
//                message（消息体）、
//                replyCode（响应code）、
//                replyText（响应内容）、
//                exchange（交换机）、
//                routingKey（队列）。

                log.info("ReturnsCallback    returned : {}",returned);
            }
        });

        return rabbitTemplate;
    }

}
